package cn.wolfcode.luowowo.search.service.impl;

import cn.wolfcode.luowowo.common.util.BeanUtil;
import cn.wolfcode.luowowo.search.query.SearchQueryObject;
import cn.wolfcode.luowowo.search.service.ISearchService;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import org.apache.commons.beanutils.BeanUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl2 implements ISearchService {

    @Autowired
    private ElasticsearchTemplate template;


    //类比:select * from xxx where  title like  %#{keyword}% or subTitle like %#{keyword}%  or summary like %#{keyword}%
    //关键字: keyword = 广州
    //以title为例:
    //原始匹配: "有娃必看,广州长隆野生动物园全攻略"
    //高亮显示后:"有娃必看,<span style="color:red;">广州</span>长隆野生动物园全攻略"

    @Override
    public <T> Page<T> searchWithHighlight(String index, String type, Class<T> clz, SearchQueryObject qo, String... fields) {
        String preTags = "<span style='color:red;'>";
        String postTags = "</span>";
        //
        HighlightBuilder.Field[] fs = new HighlightBuilder.Field[fields.length];
        for (int i = 0; i < fs.length; i++) {
            fs[i]=new HighlightBuilder.Field(fields[i]).preTags(preTags).postTags(postTags);
        }
        NativeSearchQueryBuilder searchQuery = new NativeSearchQueryBuilder();
        searchQuery.withIndices(index).//设置搜索索引
                withTypes(type);//设置搜索类型
        searchQuery.withQuery(QueryBuilders.multiMatchQuery(qo.getKeyword(),fields));//拼接查询条件
        searchQuery.withPageable(qo.getPageableNoSort());//分页操作
        searchQuery.withHighlightFields(fs);
        return  template.queryForPage(searchQuery.build(), clz, new SearchResultMapper() {
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                List<T> list = new ArrayList<>();
                SearchHits hits = response.getHits();
                SearchHit[] searchHits = hits.getHits();
                for (SearchHit searchHit : searchHits) {
                    String sourceAsString = searchHit.getSourceAsString();//拿到的是json格式的字符串
                    //仅仅是拿到原始的结果数据,此时查询字段没有高亮显示效果
                    T t = JSON.parseObject(sourceAsString, clazz);
                    //拿到高亮显示的集合//获取他高亮显示的字段和值(存放的形式是数组)
                    for (HighlightField highlightField : searchHit.getHighlightFields().values()) {
                        String name = highlightField.getName();
                        String value = highlightField.getFragments()[0].toString();//高亮显示字段的值因为都是第一个
                        try {
                            BeanUtils.setProperty(t,name,value);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                    list.add(t);
                }
                return new AggregatedPageImpl<T>((List<T>) list, pageable, response.getHits().getTotalHits());
            }
        });
    }

    private <T> void highlighlFieldsCopy(T t, Map<String, HighlightField> map, String...fields){
        Map<String,String> mm = new HashMap<>();
        for (String field : fields) {
            HighlightField hf = map.get(field);
            if(hf!=null){
                //获取高亮显示字段值,因为是一个数组,使用string拼接
                Text[] fragments = hf.fragments();
                String str="";
                for (Text text : fragments) {
                    str+=text;
                }
                mm.put(field,str);//使用map对象将所有能替换字段先缓存,后续统一替换
            }
        }
        BeanUtil.copyProperties(t,mm);
    }
}
